/* fly extension for PHP */

#ifdef HAVE_CONFIG_H
	#include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_fly.h"

#include "zend.h"
#include "zend_API.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "zend_virtual_cwd.h"

#include "php_main.h"
#include "ext/standard/php_standard.h"

#ifndef PHP_EXT
	#define PHP_EXT ".php"
#endif
zend_class_entry *flyload_ce;

//替换命名空间符号\为文件路径符号
ZEND_API void replace_ns(zend_string *class_file) {

    char *ptr = ZSTR_VAL(class_file);
    char *end = ptr + ZSTR_LEN(class_file);

    while ((ptr = memchr(ptr, '\\', (end - ptr))) != NULL) {
        *ptr = DEFAULT_SLASH;
    }
	
}
//替换PSR-0中_为文件路径符号
ZEND_API void replace_ds(zend_string *class_file) {

    char *ptr = ZSTR_VAL(class_file);
    char *end = ptr + ZSTR_LEN(class_file);

    while ((ptr = memchr(ptr, '_', (end - ptr))) != NULL) {
        *ptr = DEFAULT_SLASH;
    }
}
//通过定位字符串中\字符个数，获取类名中前缀命名空间级数
ZEND_API int get_namespace_len(zend_string *class) {
    
    int num = 0;
    
    for (int i = 0; i < ZSTR_LEN(class); i++) {
            if (ZSTR_VAL(class)[i] == '\\') {
                num++;
            }
    }
    return num;
}
//通过命名空间级数，获取指定级数命名空间
ZEND_API zend_string *get_namespace(zend_string *class,int ns_len) {
    int pos = 0 , num = 0;
    zend_string *res;
    
    if (ns_len > 0) {
        for (int i = 0; i < ZSTR_LEN(class); i++) {
            if (ZSTR_VAL(class)[i] == '\\') {
                pos = i;
                num++;
                if (num == ns_len) {
                    break;
                }
            }
        }
        if (pos > 0) {
            pos++;
            res = zend_string_alloc(pos, 1);
            memcpy(ZSTR_VAL(res), ZSTR_VAL(class), pos);
            ZSTR_VAL(res)[ZSTR_LEN(res)] = '\0';
            return res;

        }
    }
    return zend_string_init("\0",sizeof("\0") - 1,0);
}
//通过命名空间级数，获取(子)类名
ZEND_API zend_string *get_classname(zend_string *class,int ns_len) {
    
    int start = 0 , num = 0;
    zend_string *res;
    
    if (ns_len == 0) {
        return class;
    } else {
        for (int i = 0; i < ZSTR_LEN(class); i++) {
            if (ZSTR_VAL(class)[i] == '\\') {
                start = i;
                num++;
                if (num == ns_len) {
                    break;
                }
            }
        }
        if (start > 0) {
            start++;
            res = zend_string_alloc(ZSTR_LEN(class) - start + 1, 1);
            for (int j = 0;j < ZSTR_LEN(res);j++) {
                ZSTR_VAL(res)[j] = ZSTR_VAL(class)[start+j];
            }
            ZSTR_VAL(res)[ZSTR_LEN(res)] = '\0';
            return res;

        } else {
            return class;
        }
    }
}

ZEND_API int fly_include_file(zend_string *php_file,zval *retval) {
    
    zend_file_handle file_handle;
    zend_op_array *op_array;
    zend_string *opened_path;
    zval dummy,result;
	//对文件路径中分隔符进行替换
    if (ZSTR_LEN(php_file)>0){
		replace_ns(php_file);
	}
	//确定目标文件是否存在
	if (VCWD_ACCESS(ZSTR_VAL(php_file),F_OK) == -1) {
		return 0;
	}
	//如果文件已加载，直接返回
	if (zend_hash_exists(&EG(included_files),php_file)==1){
		return 0;
	}
	//初始化文件句柄file_handle
    zend_stream_init_filename(&file_handle,ZSTR_VAL(php_file));
    //如果打开读取文件成功
#if PHP_VERSION_ID > 80100
    if (zend_stream_open(&file_handle)==SUCCESS){
#else
    if (zend_stream_open(ZSTR_VAL(php_file),&file_handle)==SUCCESS){
#endif
        if (!file_handle.opened_path) {

            file_handle.opened_path = zend_string_copy(php_file);
        }
        opened_path = zend_string_copy(file_handle.opened_path);
        ZVAL_NULL(&dummy);
		//向系统EG(include_files)HASH添加文件全路径
        if (zend_hash_add(&EG(included_files), opened_path, &dummy)) {

            op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
			
         } else {
			 
            op_array = NULL;
        }
        zend_string_release_ex(opened_path, 0);
		//如果文件编译op_array成功，运行
        if (op_array) {
            
#if PHP_VERSION_ID > 80100 
            uint32_t orig_jit_trace_num = EG(jit_trace_num);
#endif 
            ZVAL_UNDEF(&result);
            zend_execute(op_array, &result);
            
#if PHP_VERSION_ID > 80100          
            EG(jit_trace_num) = orig_jit_trace_num;
#endif
            if (Z_TYPE(result) != IS_UNDEF) {
				//将运行结果返回retval
				ZVAL_COPY_VALUE(retval,&result);
                return 1;
            }
        }
    }
    zend_destroy_file_handle(&file_handle);
    return 0;
}
//原spl_autoload修改版(参考7.4.28和8.1.2)
//原参数lc_name改为文件路径
//添加lc_name定义
//参数取消文件扩展名拼接
ZEND_API int fly_autoload(zend_string *class_name, zend_string *class_file) {

    zend_string *lc_name;
    zval dummy;
    zend_file_handle file_handle;
    zend_op_array *new_op_array;
    zval result;
    int ret;
    
#if DEFAULT_SLASH != '\\'
    {
        char *ptr = ZSTR_VAL(class_file);
        char *end = ptr + ZSTR_LEN(class_file);

        while ((ptr = memchr(ptr, '\\', (end - ptr))) != NULL) {
            *ptr = DEFAULT_SLASH;
        }
    }
#endif

    zend_stream_init_filename(&file_handle, ZSTR_VAL(class_file));

#if PHP_VERSION_ID > 80100 
    ret = php_stream_open_for_zend_ex(&file_handle, USE_PATH|STREAM_OPEN_FOR_INCLUDE);
#else
    ret = php_stream_open_for_zend_ex(ZSTR_VAL(class_file), &file_handle, USE_PATH|STREAM_OPEN_FOR_INCLUDE);    
#endif 

    lc_name= zend_string_tolower(class_name);
    if (ret == SUCCESS) {
        zend_string *opened_path;
        if (!file_handle.opened_path) {

            file_handle.opened_path = zend_string_copy(class_file);
        }
        opened_path = zend_string_copy(file_handle.opened_path);
        ZVAL_NULL(&dummy);
        if (zend_hash_add(&EG(included_files), opened_path, &dummy)) {

            new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
         } else {
            new_op_array = NULL;
        }
        zend_string_release_ex(opened_path, 0);
        if (new_op_array) {
            
#if PHP_VERSION_ID > 80100 
            uint32_t orig_jit_trace_num = EG(jit_trace_num);
#endif 

            ZVAL_UNDEF(&result);
            zend_execute(new_op_array, &result);
            
#if PHP_VERSION_ID > 80100          
            EG(jit_trace_num) = orig_jit_trace_num;
#endif          

            destroy_op_array(new_op_array);
            efree(new_op_array);
            if (!EG(exception)) {
                zval_ptr_dtor(&result);
            }

            zend_destroy_file_handle(&file_handle);
            zend_string_release(class_file);
            return zend_hash_exists(EG(class_table), lc_name);
        }
    }
    zend_destroy_file_handle(&file_handle);
    zend_string_release(class_file);
    return 0;
} 


//从指定Psr4/Psr0属性映象数组中获取命名空间绝对路径
ZEND_API zval *find_namespace_paths(zval *ns_map,zend_string *namespace,int type) {
    
    zval *val;
    zend_long num;
    int ns_len;
    zend_string *key,*tmp_ns;
    
	if (type==0){
		//TYPE=0 为PSR-0命名空间key
        tmp_ns = zend_string_alloc(ZSTR_LEN(namespace)-1, 1);
        memcpy(ZSTR_VAL(tmp_ns), ZSTR_VAL(namespace), ZSTR_LEN(namespace)-1);
        ZSTR_VAL(tmp_ns)[ZSTR_LEN(tmp_ns)] = '\0';
	} else {
		//默认 为PSR-4命名空间key
		tmp_ns = zend_string_copy(namespace);
	}
	
    //检查命名空间映射ZVAL是否为HASH数组
    if (Z_TYPE_P(ns_map) == IS_ARRAY) {
        //检查命名空间映射HASH数组中，key是否为字符串
        if (zend_hash_get_current_key_type(Z_ARRVAL_P(ns_map)) == HASH_KEY_IS_STRING) {
            //遍历HASH数组（使用索引/键值对方式）
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(ns_map),num,key,val) {
				if (zend_string_equals(key,tmp_ns)) {
				//返回匹配到命名空间的路径
					return val;
					break;  
				}
            }ZEND_HASH_FOREACH_END();
        }
    }
    //如果没有找到命名空间，设定默认返回值
    ZVAL_NULL(val);
    return val;
}
//使用PSR-4规范文档方式加载类文件
static int autoload_psr(zend_string *class,zval *class_psr,int type) {
    
    zend_string *namespace,*classname,*classfile,*load_file,*lc_classname;
    int ns_len,ret=0;   
    zval *val,*namespace_paths,retval;
	
	//检测类是否已经加载过
    if (zend_hash_exists(EG(class_table), zend_string_tolower(class))) {
		return 0;
	}
    //计算命名空间长度
    ns_len=get_namespace_len(class);
	if (ns_len==0){
		return 0;
	} else {
		//为多级命名空间查找MAP
		for (int i = ns_len; i > 0;i--) {
			namespace_paths = find_namespace_paths(class_psr,get_namespace(class,i),type);
			if (Z_TYPE_P(namespace_paths)==IS_ARRAY){
				namespace=get_namespace(class,i);
				classname=get_classname(class,i);
				break;
			}
			
		}
	}
		//检测是否找到PSR-4命名空间路径
    if (Z_TYPE_P(namespace_paths) != IS_NULL) {
        //检测找到的路径是否为HASH数组
        if (Z_TYPE_P(namespace_paths) == IS_ARRAY) {
            //检测HASH数组中key是否为索引数组
            if (zend_hash_get_current_key_type(Z_ARRVAL_P(namespace_paths)) == HASH_KEY_IS_LONG) {
                //进行路径HASH数据遍历
                ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(namespace_paths),val) {
					lc_classname = zend_strpprintf(0, "%s%c%s%s", Z_STRVAL_P(val),DEFAULT_SLASH,ZSTR_VAL(classname),PHP_EXT);
#if DEFAULT_SLASH != '\\'
					replace_ns(lc_classname);
#endif

					if (VCWD_ACCESS(ZSTR_VAL(lc_classname),F_OK) != -1) {
 						ZVAL_UNDEF(&retval);
						ret = fly_autoload(class,lc_classname);
					}
					if (ret == 1) {
                        break;
                    }
                }ZEND_HASH_FOREACH_END();

            }
        }
    }
    return ret;
}
//从指定classmap属性映象数组中获取无命名空间类名绝对路径并加载文件
static int autoload_class_for_map(zval *class_map,zend_string *class) {
    
    zval *val,*path_val,retval;
    zend_long num;
    zend_string *key,*lc_classname;
    int ret = 0;
    
    //检查类映射ZVAL是否为HASH数组
    if (Z_TYPE_P(class_map) == IS_ARRAY) {
        //检查命名空间映射HASH数组中，key是否为字符串     
        if (zend_hash_get_current_key_type(Z_ARRVAL_P(class_map)) == HASH_KEY_IS_STRING) {
            //遍历HASH数组（使用索引/键值对方式）
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(class_map),num,key,val) {
               //检测HASH数组中key是否为当前命名空间
                if (zend_string_equals(key,class)) {
                    //如果检测到的命名空间路径为数组，再次遍历
                    if (Z_TYPE_P(val) == IS_ARRAY) {
                        //使用HASH数组值进行遍历
                        ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val),path_val) {
                            //将所有文件进行加载
                            lc_classname = zend_string_init(Z_STRVAL_P(path_val),Z_STRLEN_P(path_val),0);
							if (VCWD_ACCESS(ZSTR_VAL(lc_classname),F_OK) != -1) {
								ZVAL_UNDEF(&retval);
								ret = fly_include_file(lc_classname,&retval);
							}
							zend_string_release(lc_classname);
					if (ret == 1) {
                        break;
                    }
                        }ZEND_HASH_FOREACH_END();
                    }
                }
                if (ret == 1) {
                    break;
                }
            }ZEND_HASH_FOREACH_END();
        }
    }
    return ret;
}

static int fly_load_composer_config(zval *object_t,zend_string *root,char *property,zend_string *file) {
	
    zval *obj_t;	
	zend_string *autoload_file;
	zval retval,*classmap_arr=&retval;
	//检查默认目录下是否有composer的文件
	autoload_file = zend_strpprintf(0, "%s%s", ZSTR_VAL(root),ZSTR_VAL(file));
	//确定目标文件是否存在
	if (VCWD_ACCESS(ZSTR_VAL(autoload_file),F_OK) != -1) {
		if (fly_include_file(autoload_file,&retval)){
			if (Z_TYPE(retval)==IS_ARRAY) {
		
#if PHP_VERSION_ID > 80100 
				zend_update_property(flyload_ce, Z_OBJ_P(object_t), property, sizeof(property)-1,classmap_arr);
#else
				zend_update_property(flyload_ce, object_t, property, sizeof(property)-1, classmap_arr);
#endif
			}
		}
	}
	zend_string_release_ex(autoload_file,0);
}


/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
    ZEND_PARSE_PARAMETERS_START(0, 0) \
    ZEND_PARSE_PARAMETERS_END()
#endif

//FlyLoad类初初始化定义：$loader=new FlyLoad();
//参数可选，定义为vendor目录所在绝对路径，并复制到$loader->root属性
ZEND_METHOD(FlyLoad,__construct) {
    zend_string *root;
    zval *obj_t;
    
    ZEND_PARSE_PARAMETERS_START(0, 1)
        Z_PARAM_OPTIONAL
        Z_PARAM_STR(root)
    ZEND_PARSE_PARAMETERS_END();
    
    obj_t=getThis();
    
    if (root) {
#if PHP_VERSION_ID > 80100 
        zend_update_property_string(flyload_ce, Z_OBJ_P(obj_t), "root", sizeof("root")-1, ZSTR_VAL(root));
#else
        zend_update_property_string(flyload_ce, obj_t, "root", sizeof("root")-1, ZSTR_VAL(root));
#endif    
    }
}

ZEND_METHOD(FlyLoad,loadClass) {
	
    int ce,rt=0;
    zend_string *class,*lc_classname;
    zval *root,*class_psr4,*class_psr0,*class_map,*is_use,rv,retval;
    
    ZEND_PARSE_PARAMETERS_START(1,1)
        Z_PARAM_STR(class)
    ZEND_PARSE_PARAMETERS_END();

    zval *object_t=getThis();

    //检测加载类，是否在系统类列表里已经存在
    ce = zend_hash_exists(EG(class_table), zend_string_tolower(class));
 
    if (ce != 0) {
        RETURN_TRUE;
    } else {
        //获取flyload类的基本属性值
#if PHP_VERSION_ID > 80100 
        root=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"root",sizeof("root")-1,0,&rv);
        class_psr4=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"psr4map",sizeof("psr4map")-1,0,&rv);
        class_psr0=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"psr0map",sizeof("psr0map")-1,0,&rv);
        class_map=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"classmap",sizeof("classmap")-1,0,&rv);
        is_use=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"usemap",sizeof("usemap")-1,0,&rv);
#else
        root=zend_read_property(flyload_ce,object_t,"root",sizeof("root")-1,0,&rv  TSRMLS_DC);
        class_psr4=zend_read_property(flyload_ce,object_t,"psr4map",sizeof("psr4map")-1,0,&rv  TSRMLS_DC);
        class_psr0=zend_read_property(flyload_ce,object_t,"psr0map",sizeof("psr0map")-1,0,&rv  TSRMLS_DC);
        class_map=zend_read_property(flyload_ce,object_t,"classmap",sizeof("classmap")-1,0,&rv  TSRMLS_DC);
        is_use=zend_read_property(flyload_ce,object_t,"usemap",sizeof("usemap")-1,0,&rv  TSRMLS_DC);
    
#endif
        //检测root属性是否被设置
        if (Z_TYPE_P(root) != IS_NULL) {
            //检测root属性是否为字符串类型
            if (Z_TYPE_P(root) == IS_STRING) {
                //检测是否使用composer方法加载类
                if (Z_TYPE_P(is_use) == IS_TRUE) {
                    //尝试加载无命名空间类
                    if ((Z_TYPE_P(class_map) == IS_ARRAY) && (rt == 0)) {
                        rt=autoload_class_for_map(class_map,class);
                    }
                    //尝试加载PSR-4命名空间类
                    if ((Z_TYPE_P(class_psr4) == IS_ARRAY) && (rt == 0)) {
                        rt=autoload_psr(class,class_psr4,1);
                    }
                     //尝试加载PSR-0命名空间类
                     if ((Z_TYPE_P(class_psr0) == IS_ARRAY) && (rt == 0)) {
                        rt=autoload_psr(class,class_psr0,0);
                    }
                
                }
				if (rt == 0) {
                    //默认使用PSR-4方式加载root下的类
                    lc_classname = zend_strpprintf(0, "%s%c%s%s", Z_STRVAL_P(root),DEFAULT_SLASH,ZSTR_VAL(class),PHP_EXT);
                    rt = fly_include_file(lc_classname,&retval);
                }                   
            } else {
                zend_error(E_ERROR,"root property's TYPE not string!\n");
            }
        } else {
            zend_error(E_ERROR,"root property's value is NULL!\n");
        }
    }
}

ZEND_METHOD(FlyLoad,run) {
    
    zval *root,*file_map,*val,*path_val,rv,retval;
    int num,st;
    zend_string *key,*lc_classname,*root_path;

    zval *rt,*object_t=getThis();
    
    //读取filemap属性映射的HASH数组
#if PHP_VERSION_ID > 80100 
    file_map = zend_read_property(flyload_ce,Z_OBJ_P(object_t),"filemap",sizeof("filemap")-1,0,&rv);
    root=zend_read_property(flyload_ce,Z_OBJ_P(object_t),"root",sizeof("root")-1,0,&rv);
#else
    file_map = zend_read_property(flyload_ce,object_t,"filemap",sizeof("filemap")-1,0,&rv TSRMLS_DC);
   root=zend_read_property(flyload_ce,object_t,"root",sizeof("root")-1,0,&rv  TSRMLS_DC);
#endif
   root_path=zend_string_init(Z_STRVAL_P(root),Z_STRLEN_P(root),0);
 		zend_string *psr4map_file=zend_string_init("/vendor/composer/autoload_psr4.php",sizeof("/vendor/composer/autoload_psr4.php")-1,0);
		zend_string *psr0map_file=zend_string_init("/vendor/composer/autoload_namespaces.php",sizeof("/vendor/composer/autoload_namespaces.php")-1,0);
		zend_string *classmap_file=zend_string_init("/vendor/composer/autoload_classmap.php",sizeof("/vendor/composer/autoload_classmap.php")-1,0);
		zend_string *filemap_file=zend_string_init("/vendor/composer/autoload_files.php",sizeof("/vendor/composer/autoload_files.php")-1,0);
		fly_load_composer_config(object_t,root_path,"psr4map",psr4map_file);
		fly_load_composer_config(object_t,root_path,"psr0map",psr0map_file);
		fly_load_composer_config(object_t,root_path,"classmap",classmap_file);
		fly_load_composer_config(object_t,root_path,"filemap",filemap_file);

    //检测filemap属性是否为数组
	if (Z_TYPE_P(file_map) == IS_ARRAY) {
         //检测filemap属性HASH数组的key是否为字符串
        if (zend_hash_get_current_key_type(Z_ARRVAL_P(file_map)) == HASH_KEY_IS_STRING) {
            //遍历HASH数组（使用索引/键值对方式）
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(file_map),num,key,val) {
                //根据HASH数组value值是否为数据和字符串进行加载
                if (Z_TYPE_P(val) == IS_ARRAY) {
                    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val),path_val) {
                        lc_classname = zend_string_init(Z_STRVAL_P(path_val),Z_STRLEN_P(path_val),0);
                        st = fly_include_file(lc_classname,&retval);
						if (st){
							break;
						}
                    }ZEND_HASH_FOREACH_END();
                } else if (Z_TYPE_P(val) == IS_STRING) {
                        lc_classname = zend_string_init(Z_STRVAL_P(val),Z_STRLEN_P(val),0);
                        st = fly_include_file(lc_classname,&retval);
                }

            }ZEND_HASH_FOREACH_END();
        }
    }  
}

//向系统注册本类为自动加载类
ZEND_METHOD(FlyLoad,register) {
    
    zval arg;//参数
    array_init(&arg);//初始化数据，

    add_next_index_zval(&arg, getThis());
    add_next_index_string(&arg, "loadClass");//当前类的中load的方法，表态方法（ZEND_ACC_static）

    zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload_register", NULL, &arg);

    zval_ptr_dtor(&arg);
}
//读取filemap属性映射的自定义函数
#if PHP_VERSION_ID > 80000

    ZEND_BEGIN_ARG_INFO_EX(arginfo_default___construct,0,0,1)
        ZEND_ARG_TYPE_INFO(0, root , IS_STRING, 0)
    ZEND_END_ARG_INFO()
    
    ZEND_BEGIN_ARG_INFO_EX(arginfo_default_loadClass, 0,0,1)
        ZEND_ARG_TYPE_INFO(0, class , IS_STRING, 0)
    ZEND_END_ARG_INFO()

    ZEND_BEGIN_ARG_INFO_EX(arginfo_default_none, 0, 0, 0)
    ZEND_END_ARG_INFO()


#else

    ZEND_BEGIN_ARG_INFO(arginfo_default___construct, 0)
        ZEND_ARG_INFO(0, root)
    ZEND_END_ARG_INFO()
    ZEND_BEGIN_ARG_INFO(arginfo_default_loadClass, 1)
        ZEND_ARG_INFO(0, class)
    ZEND_END_ARG_INFO()
    
    ZEND_BEGIN_ARG_INFO(arginfo_default_none, 0)
    ZEND_END_ARG_INFO()

#endif
/* {{{ flyload_functions[]
 */
static const zend_function_entry flyload_functions[] = {
    ZEND_ME(FlyLoad,__construct,    arginfo_default___construct,	ZEND_ACC_PUBLIC)
    ZEND_ME(FlyLoad,loadClass,  	arginfo_default_loadClass,		ZEND_ACC_PUBLIC)
    ZEND_ME(FlyLoad,register,   	arginfo_default_none,			ZEND_ACC_PUBLIC)
    ZEND_ME(FlyLoad,run,			arginfo_default_none,			ZEND_ACC_PUBLIC)
    ZEND_FE_END
};
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(fly)
{
    //flyload类声明
    zend_class_entry flyload;
    //默认开启composer
    zend_long is_active = 1;
    //flyload类初始化
    INIT_CLASS_ENTRY(flyload,"FlyLoad",flyload_functions);
    //flyload注册类
    flyload_ce=zend_register_internal_class_ex(&flyload,NULL);
    //添加root属性,根目录
    zend_declare_property_null(flyload_ce,"root",sizeof("root")-1,ZEND_ACC_PUBLIC);
    //添加composer加载器属性
    zend_declare_property_null(flyload_ce,"psr0map",sizeof("psr0map")-1,ZEND_ACC_PUBLIC);
    zend_declare_property_null(flyload_ce,"psr4map",sizeof("psr4map")-1,ZEND_ACC_PUBLIC);
    zend_declare_property_null(flyload_ce,"classmap",sizeof("classmap")-1,ZEND_ACC_PUBLIC);
    zend_declare_property_null(flyload_ce,"filemap",sizeof("filemap")-1,ZEND_ACC_PUBLIC);
    //添加是否启用composer属性
    zend_declare_property_bool(flyload_ce,"usemap",sizeof("usemap")-1,is_active,ZEND_ACC_PUBLIC);
    return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(fly)
{

}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(fly)
{
#if defined(ZTS) && defined(COMPILE_DL_FLY)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif

    return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(fly)
{

}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(fly)
{
    php_info_print_table_start();
	php_info_print_table_header(2, "Directive", "Info");
    php_info_print_table_row(2, "FlyLoad support", "enabled");
    php_info_print_table_row(2, "Version", PHP_FLY_VERSION);
    php_info_print_table_row(2, "Author", "A_knife(Lingjun Kong)");
    php_info_print_table_row(2, "Create", "2025-04-01");
    php_info_print_table_end();
}
/* }}} */

/* {{{ arginfo
 */
ZEND_BEGIN_ARG_INFO(arginfo_fly_include, 1)
    ZEND_ARG_INFO(0, php_file)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_fly_display, 0)
    ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ void fly_test1()
 */
PHP_FUNCTION(fly_include)
{
    zend_string *php_file;
    zval retval,*ret=&retval;
    
    ZEND_PARSE_PARAMETERS_START(1,1)
        Z_PARAM_STR(php_file)
    ZEND_PARSE_PARAMETERS_END();

    fly_include_file(php_file,&retval);
    
    RETURN_ZVAL(ret,0,0);
}
/* }}} */

/* {{{ fly_functions[]
 */
static const zend_function_entry fly_functions[] = {
    ZEND_FE(fly_include,    arginfo_fly_include)
    ZEND_FE_END
};
/* }}} */

/* {{{ fly_module_entry
 */
zend_module_entry fly_module_entry = {
    STANDARD_MODULE_HEADER,
    "fly",                  /* Extension name */
    fly_functions,          /* zend_function_entry */
    PHP_MINIT(fly),         /* PHP_MINIT - Module initialization */
    PHP_MSHUTDOWN(fly),     /* PHP_MSHUTDOWN - Module shutdown */
    PHP_RINIT(fly),         /* PHP_RINIT - Request initialization */
    PHP_RSHUTDOWN(fly),     /* PHP_RSHUTDOWN - Request shutdown */
    PHP_MINFO(fly),         /* PHP_MINFO - Module info */
    PHP_FLY_VERSION,        /* Version */
    STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_FLY
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(fly)
#endif
